/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.flexengine.sound;

import com.flexengine.logger.Logger;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.advanced.AdvancedPlayer;

/**
 * @author Luann R. Athayde
 * @version 1.0
 * @since 1.0
 */
public class SoundPlayer {
    
    private Sound            sound;
    private AudioFormat      format;
    private boolean          paused;
    private boolean          playing;
    
    private AdvancedPlayer   aPlayer;
    
    protected SoundPlayer(Sound sound) {
        try {
            this.sound = sound;
            this.format = sound.getSoundFormat();
            this.paused = false;
            this.playing = false;
            aPlayer = null;
        } catch(Exception e) {
            Logger.logError(getClass().getSimpleName()+": "+e);
        }
    }
    
    protected synchronized void play(InputStream source) {
        if( source==null) {
            return;
        }
        if( sound.getSoundType()!=Sound.SOUND_TYPE_MP3 && format != null ) {
            int bufferSize = format.getFrameSize() * Math.round(format.getSampleRate()/10);
            byte buffer[] = new byte[bufferSize];
            //----------------------------------------------------------------------
            // -- Create a source line to play...
            SourceDataLine line;
            try {
                DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
                line = (SourceDataLine)AudioSystem.getLine(info);
                line.open(format, bufferSize);

                // -- start line...
                line.start();

                // copy data to line...
                playing = true;
                int numBytesRead = 0;
                while( numBytesRead != -1 && playing ) {
                    numBytesRead = source.read(buffer, 0, buffer.length);
                    if( numBytesRead != -1) {
                        if( paused ) {
                            wait();
                        }
                        line.write(buffer, 0, numBytesRead);
                    }
                }

                // wait until all data is played...
                line.drain();
                // stop...
                line.stop();
                // --
                // close the line...
                line.close();
            } catch(LineUnavailableException | IOException | InterruptedException e) {
                Logger.logError(getClass().getSimpleName()+" - play(): "+e);
            }
        } else {
            try {
                aPlayer = new AdvancedPlayer(source);
                aPlayer.play();
            } catch (JavaLayerException ex) {
                Logger.logError(getClass().getSimpleName()+" - play(): Error with try playing ["+sound+"]...\n"
                        + "\tException: "+ex);
            }
        }
    }

    protected synchronized void play() {
        paused = false;
        this.notifyAll();
        try {
            aPlayer.play();
        } catch (JavaLayerException ex) {
            Logger.logError(getClass()+"- play(): "+ex);
        }
    }
    
    public void stop() {
        playing = false;
        try {
            aPlayer.close();
        } catch (Exception ex) {
        }
    }
    
    public void pause() {
        paused = true;
        try {
            aPlayer.stop();
        } catch (Exception ex) {
        }
    }

    public Sound getSound() {
        return sound;
    }

    public boolean isPaused() {
        return paused;
    }

    public boolean isPlaying() {
        return playing;
    }
    
}
